var fs = require('fs');

var myArgs = process.argv.slice(1);

POI = function(nm, lt, lg, r){
	this.name = nm;
	this.lat = lt;
	this.lng = lg;
	this.ratings = r;
}
	
POI.prototype.averageRatings = function(){
		if(this.ratings.length > 0){
			var m = 0.0;
			for(var idx = 0; idx < this.ratings.length; idx++){
				m += parseInt(this.ratings[idx]);
			}
			return (m / this.ratings.length);
		}
		return 0;
	};
	
POI.prototype.addRating = function(rating){
		this.ratings.push(rating);
	};

// The list of POI pared from the input file.
parsedPOI = []

symb = ["START_POI","name","latlng","note","END_POI","$$"];


var fileToParse = myArgs[1];


fs.readFile(fileToParse, 'utf8', function (err,data) {
  if (err) {
    return console.log(err);
  }
  
  
  parse(data);
  console.log("fileToParse is a valid vpf file");
  console.log(parsedPOI);
  
  for(var idx = 0; idx < parsedPOI.length; idx++){
	console.log(parsedPOI[idx].name+": "+parsedPOI[idx].averageRatings());
  }

});



// Parser procedure

// tokenize : tranform the data input into a list
function tokenize(data){
	return data.split(/\r\n|: /);
}

// parse : analyze data by calling the first non terminal rule of the grammar
function parse(data){
	var tData = tokenize(data);
	//console.log(tData);
	listPoi(tData);
}

// Parser operand

function err(msg, input){
	console.log("Parsing Error ! on "+input[0]+" -- msg : "+msg);
	process.exit(0);
}

function next(input){
	var curS = input.shift();
	//console.log(curS);
	return curS
}

// accept : verify if the arg s is part of the language symbols.
function accept(s){
	var idx = symb.indexOf(s);
	// index 0 exists
	if(idx >= 0){
		return idx;
	}
	err("symbol "+s+" unknown", [" "]);
	return false;
}

// check : check whether the arg elt is on the head of the list
function check(elt, input){
	if(accept(input[0]) == accept(elt)){
		return true;	
	}
	return false;
}

// expect : expect the next symbol to be s.
function expect(s, input){
	if(s == next(input)){
		//console.log("Reckognized! "+s)
		return true;
	}else{
		err("symbol "+s+" doesn't match", input);
	}
	return false;
}


// Parser rules

function listPoi(input){
	poi(input);
	expect("$$", input);
}

function poi(input){

	if(check("START_POI", input)){
		expect("START_POI", input);
		var args = body(input);
		var p = new POI(args.nm, args.lt, args.lg, []);
		note(input, p);
		expect("END_POI",input);
		parsedPOI.push(p);
		poi(input);
		return true;
	}else{
		return false;
	}

}

function body(input){
	var nm = name(input);
	var ltlg =latlng(input);
	return { nm: nm, lt: ltlg.lat, lg: ltlg.lng };
}

exports.name = function name(input){
	expect("name",input)
	var curS = next(input);
	if(matched = curS.match(/[\w\s]+/i)){
		return matched[0];
	}else{
		err("Invalid name", input);
	}
}

exports.latlng = function latlng(input){
	expect("latlng",input)
	var curS = next(input);
	if(matched = curS.match(/-?(\d+(\.\d+)?);(-?\d+(\.\d+)?)/)){
		return { lat: matched[1], lng: matched[3] };
	}else{
		err("Invalid latlng", input);
	}
}

function note(input, curPoi){
	if(check("note", input)){
		expect("note", input);
		var curS = next(input);
		if(matched = curS.match(/\d/)){
			curPoi.addRating(matched[0]);
			note(input, curPoi);
		}else{
			err("Invalid note");
		}	
	}
}

